Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   1/*
   2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
   3 * Authors:
   4 * Seung-Woo Kim <sw0312.kim@samsung.com>
   5 *	Inki Dae <inki.dae@samsung.com>
   6 *	Joonyoung Shim <jy0922.shim@samsung.com>
   7 *
   8 * Based on drivers/media/video/s5p-tv/mixer_reg.c
   9 *
  10 * This program is free software; you can redistribute  it and/or modify it
  11 * under  the terms of  the GNU General  Public License as published by the
  12 * Free Software Foundation;  either version 2 of the  License, or (at your
  13 * option) any later version.
  14 *
  15 */
  16
  17#include "drmP.h"
  18
  19#include "regs-mixer.h"
  20#include "regs-vp.h"
  21
  22#include <linux/kernel.h>
  23#include <linux/spinlock.h>
  24#include <linux/wait.h>
  25#include <linux/i2c.h>
  26#include <linux/module.h>
  27#include <linux/platform_device.h>
  28#include <linux/interrupt.h>
  29#include <linux/irq.h>
  30#include <linux/delay.h>
  31#include <linux/pm_runtime.h>
  32#include <linux/clk.h>
  33#include <linux/regulator/consumer.h>
  34
  35#include <drm/exynos_drm.h>
  36
  37#include "exynos_drm_drv.h"
  38#include "exynos_drm_hdmi.h"
  39
  40#define get_mixer_context(dev)	platform_get_drvdata(to_platform_device(dev))
  41
  42struct hdmi_win_data {
  43	dma_addr_t		dma_addr;
  44	void __iomem		*vaddr;
  45	dma_addr_t		chroma_dma_addr;
  46	void __iomem		*chroma_vaddr;
  47	uint32_t		pixel_format;
  48	unsigned int		bpp;
  49	unsigned int		crtc_x;
  50	unsigned int		crtc_y;
  51	unsigned int		crtc_width;
  52	unsigned int		crtc_height;
  53	unsigned int		fb_x;
  54	unsigned int		fb_y;
  55	unsigned int		fb_width;
  56	unsigned int		fb_height;
  57	unsigned int		src_width;
  58	unsigned int		src_height;
  59	unsigned int		mode_width;
  60	unsigned int		mode_height;
  61	unsigned int		scan_flags;
  62};
  63
  64struct mixer_resources {
  65	int			irq;
  66	void __iomem		*mixer_regs;
  67	void __iomem		*vp_regs;
  68	spinlock_t		reg_slock;
  69	struct clk		*mixer;
  70	struct clk		*vp;
  71	struct clk		*sclk_mixer;
  72	struct clk		*sclk_hdmi;
  73	struct clk		*sclk_dac;
  74};
  75
  76struct mixer_context {
  77	struct device		*dev;
  78	int			pipe;
  79	bool			interlace;
  80	bool			powered;
  81	u32			int_en;
  82
  83	struct mutex		mixer_mutex;
  84	struct mixer_resources	mixer_res;
  85	struct hdmi_win_data	win_data[MIXER_WIN_NR];
  86};
  87
  88static const u8 filter_y_horiz_tap8[] = {
  89	0,	-1,	-1,	-1,	-1,	-1,	-1,	-1,
  90	-1,	-1,	-1,	-1,	-1,	0,	0,	0,
  91	0,	2,	4,	5,	6,	6,	6,	6,
  92	6,	5,	5,	4,	3,	2,	1,	1,
  93	0,	-6,	-12,	-16,	-18,	-20,	-21,	-20,
  94	-20,	-18,	-16,	-13,	-10,	-8,	-5,	-2,
  95	127,	126,	125,	121,	114,	107,	99,	89,
  96	79,	68,	57,	46,	35,	25,	16,	8,
  97};
  98
  99static const u8 filter_y_vert_tap4[] = {
 100	0,	-3,	-6,	-8,	-8,	-8,	-8,	-7,
 101	-6,	-5,	-4,	-3,	-2,	-1,	-1,	0,
 102	127,	126,	124,	118,	111,	102,	92,	81,
 103	70,	59,	48,	37,	27,	19,	11,	5,
 104	0,	5,	11,	19,	27,	37,	48,	59,
 105	70,	81,	92,	102,	111,	118,	124,	126,
 106	0,	0,	-1,	-1,	-2,	-3,	-4,	-5,
 107	-6,	-7,	-8,	-8,	-8,	-8,	-6,	-3,
 108};
 109
 110static const u8 filter_cr_horiz_tap4[] = {
 111	0,	-3,	-6,	-8,	-8,	-8,	-8,	-7,
 112	-6,	-5,	-4,	-3,	-2,	-1,	-1,	0,
 113	127,	126,	124,	118,	111,	102,	92,	81,
 114	70,	59,	48,	37,	27,	19,	11,	5,
 115};
 116
 117static inline u32 vp_reg_read(struct mixer_resources *res, u32 reg_id)
 118{
 119	return readl(res->vp_regs + reg_id);
 120}
 121
 122static inline void vp_reg_write(struct mixer_resources *res, u32 reg_id,
 123				 u32 val)
 124{
 125	writel(val, res->vp_regs + reg_id);
 126}
 127
 128static inline void vp_reg_writemask(struct mixer_resources *res, u32 reg_id,
 129				 u32 val, u32 mask)
 130{
 131	u32 old = vp_reg_read(res, reg_id);
 132
 133	val = (val & mask) | (old & ~mask);
 134	writel(val, res->vp_regs + reg_id);
 135}
 136
 137static inline u32 mixer_reg_read(struct mixer_resources *res, u32 reg_id)
 138{
 139	return readl(res->mixer_regs + reg_id);
 140}
 141
 142static inline void mixer_reg_write(struct mixer_resources *res, u32 reg_id,
 143				 u32 val)
 144{
 145	writel(val, res->mixer_regs + reg_id);
 146}
 147
 148static inline void mixer_reg_writemask(struct mixer_resources *res,
 149				 u32 reg_id, u32 val, u32 mask)
 150{
 151	u32 old = mixer_reg_read(res, reg_id);
 152
 153	val = (val & mask) | (old & ~mask);
 154	writel(val, res->mixer_regs + reg_id);
 155}
 156
 157static void mixer_regs_dump(struct mixer_context *ctx)
 158{
 159#define DUMPREG(reg_id) \
 160do { \
 161	DRM_DEBUG_KMS(#reg_id " = %08x\n", \
 162		(u32)readl(ctx->mixer_res.mixer_regs + reg_id)); \
 163} while (0)
 164
 165	DUMPREG(MXR_STATUS);
 166	DUMPREG(MXR_CFG);
 167	DUMPREG(MXR_INT_EN);
 168	DUMPREG(MXR_INT_STATUS);
 169
 170	DUMPREG(MXR_LAYER_CFG);
 171	DUMPREG(MXR_VIDEO_CFG);
 172
 173	DUMPREG(MXR_GRAPHIC0_CFG);
 174	DUMPREG(MXR_GRAPHIC0_BASE);
 175	DUMPREG(MXR_GRAPHIC0_SPAN);
 176	DUMPREG(MXR_GRAPHIC0_WH);
 177	DUMPREG(MXR_GRAPHIC0_SXY);
 178	DUMPREG(MXR_GRAPHIC0_DXY);
 179
 180	DUMPREG(MXR_GRAPHIC1_CFG);
 181	DUMPREG(MXR_GRAPHIC1_BASE);
 182	DUMPREG(MXR_GRAPHIC1_SPAN);
 183	DUMPREG(MXR_GRAPHIC1_WH);
 184	DUMPREG(MXR_GRAPHIC1_SXY);
 185	DUMPREG(MXR_GRAPHIC1_DXY);
 186#undef DUMPREG
 187}
 188
 189static void vp_regs_dump(struct mixer_context *ctx)
 190{
 191#define DUMPREG(reg_id) \
 192do { \
 193	DRM_DEBUG_KMS(#reg_id " = %08x\n", \
 194		(u32) readl(ctx->mixer_res.vp_regs + reg_id)); \
 195} while (0)
 196
 197	DUMPREG(VP_ENABLE);
 198	DUMPREG(VP_SRESET);
 199	DUMPREG(VP_SHADOW_UPDATE);
 200	DUMPREG(VP_FIELD_ID);
 201	DUMPREG(VP_MODE);
 202	DUMPREG(VP_IMG_SIZE_Y);
 203	DUMPREG(VP_IMG_SIZE_C);
 204	DUMPREG(VP_PER_RATE_CTRL);
 205	DUMPREG(VP_TOP_Y_PTR);
 206	DUMPREG(VP_BOT_Y_PTR);
 207	DUMPREG(VP_TOP_C_PTR);
 208	DUMPREG(VP_BOT_C_PTR);
 209	DUMPREG(VP_ENDIAN_MODE);
 210	DUMPREG(VP_SRC_H_POSITION);
 211	DUMPREG(VP_SRC_V_POSITION);
 212	DUMPREG(VP_SRC_WIDTH);
 213	DUMPREG(VP_SRC_HEIGHT);
 214	DUMPREG(VP_DST_H_POSITION);
 215	DUMPREG(VP_DST_V_POSITION);
 216	DUMPREG(VP_DST_WIDTH);
 217	DUMPREG(VP_DST_HEIGHT);
 218	DUMPREG(VP_H_RATIO);
 219	DUMPREG(VP_V_RATIO);
 220
 221#undef DUMPREG
 222}
 223
 224static inline void vp_filter_set(struct mixer_resources *res,
 225		int reg_id, const u8 *data, unsigned int size)
 226{
 227	/* assure 4-byte align */
 228	BUG_ON(size & 3);
 229	for (; size; size -= 4, reg_id += 4, data += 4) {
 230		u32 val = (data[0] << 24) |  (data[1] << 16) |
 231			(data[2] << 8) | data[3];
 232		vp_reg_write(res, reg_id, val);
 233	}
 234}
 235
 236static void vp_default_filter(struct mixer_resources *res)
 237{
 238	vp_filter_set(res, VP_POLY8_Y0_LL,
 239		filter_y_horiz_tap8, sizeof filter_y_horiz_tap8);
 240	vp_filter_set(res, VP_POLY4_Y0_LL,
 241		filter_y_vert_tap4, sizeof filter_y_vert_tap4);
 242	vp_filter_set(res, VP_POLY4_C0_LL,
 243		filter_cr_horiz_tap4, sizeof filter_cr_horiz_tap4);
 244}
 245
 246static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable)
 247{
 248	struct mixer_resources *res = &ctx->mixer_res;
 249
 250	/* block update on vsync */
 251	mixer_reg_writemask(res, MXR_STATUS, enable ?
 252			MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE);
 253
 254	vp_reg_write(res, VP_SHADOW_UPDATE, enable ?
 255			VP_SHADOW_UPDATE_ENABLE : 0);
 256}
 257
 258static void mixer_cfg_scan(struct mixer_context *ctx, unsigned int height)
 259{
 260	struct mixer_resources *res = &ctx->mixer_res;
 261	u32 val;
 262
 263	/* choosing between interlace and progressive mode */
 264	val = (ctx->interlace ? MXR_CFG_SCAN_INTERLACE :
 265				MXR_CFG_SCAN_PROGRASSIVE);
 266
 267	/* choosing between porper HD and SD mode */
 268	if (height == 480)
 269		val |= MXR_CFG_SCAN_NTSC | MXR_CFG_SCAN_SD;
 270	else if (height == 576)
 271		val |= MXR_CFG_SCAN_PAL | MXR_CFG_SCAN_SD;
 272	else if (height == 720)
 273		val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
 274	else if (height == 1080)
 275		val |= MXR_CFG_SCAN_HD_1080 | MXR_CFG_SCAN_HD;
 276	else
 277		val |= MXR_CFG_SCAN_HD_720 | MXR_CFG_SCAN_HD;
 278
 279	mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_SCAN_MASK);
 280}
 281
 282static void mixer_cfg_rgb_fmt(struct mixer_context *ctx, unsigned int height)
 283{
 284	struct mixer_resources *res = &ctx->mixer_res;
 285	u32 val;
 286
 287	if (height == 480) {
 288		val = MXR_CFG_RGB601_0_255;
 289	} else if (height == 576) {
 290		val = MXR_CFG_RGB601_0_255;
 291	} else if (height == 720) {
 292		val = MXR_CFG_RGB709_16_235;
 293		mixer_reg_write(res, MXR_CM_COEFF_Y,
 294				(1 << 30) | (94 << 20) | (314 << 10) |
 295				(32 << 0));
 296		mixer_reg_write(res, MXR_CM_COEFF_CB,
 297				(972 << 20) | (851 << 10) | (225 << 0));
 298		mixer_reg_write(res, MXR_CM_COEFF_CR,
 299				(225 << 20) | (820 << 10) | (1004 << 0));
 300	} else if (height == 1080) {
 301		val = MXR_CFG_RGB709_16_235;
 302		mixer_reg_write(res, MXR_CM_COEFF_Y,
 303				(1 << 30) | (94 << 20) | (314 << 10) |
 304				(32 << 0));
 305		mixer_reg_write(res, MXR_CM_COEFF_CB,
 306				(972 << 20) | (851 << 10) | (225 << 0));
 307		mixer_reg_write(res, MXR_CM_COEFF_CR,
 308				(225 << 20) | (820 << 10) | (1004 << 0));
 309	} else {
 310		val = MXR_CFG_RGB709_16_235;
 311		mixer_reg_write(res, MXR_CM_COEFF_Y,
 312				(1 << 30) | (94 << 20) | (314 << 10) |
 313				(32 << 0));
 314		mixer_reg_write(res, MXR_CM_COEFF_CB,
 315				(972 << 20) | (851 << 10) | (225 << 0));
 316		mixer_reg_write(res, MXR_CM_COEFF_CR,
 317				(225 << 20) | (820 << 10) | (1004 << 0));
 318	}
 319
 320	mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_RGB_FMT_MASK);
 321}
 322
 323static void mixer_cfg_layer(struct mixer_context *ctx, int win, bool enable)
 324{
 325	struct mixer_resources *res = &ctx->mixer_res;
 326	u32 val = enable ? ~0 : 0;
 327
 328	switch (win) {
 329	case 0:
 330		mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP0_ENABLE);
 331		break;
 332	case 1:
 333		mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_GRP1_ENABLE);
 334		break;
 335	case 2:
 336		vp_reg_writemask(res, VP_ENABLE, val, VP_ENABLE_ON);
 337		mixer_reg_writemask(res, MXR_CFG, val, MXR_CFG_VP_ENABLE);
 338		break;
 339	}
 340}
 341
 342static void mixer_run(struct mixer_context *ctx)
 343{
 344	struct mixer_resources *res = &ctx->mixer_res;
 345
 346	mixer_reg_writemask(res, MXR_STATUS, ~0, MXR_STATUS_REG_RUN);
 347
 348	mixer_regs_dump(ctx);
 349}
 350
 351static void vp_video_buffer(struct mixer_context *ctx, int win)
 352{
 353	struct mixer_resources *res = &ctx->mixer_res;
 354	unsigned long flags;
 355	struct hdmi_win_data *win_data;
 356	unsigned int x_ratio, y_ratio;
 357	unsigned int buf_num;
 358	dma_addr_t luma_addr[2], chroma_addr[2];
 359	bool tiled_mode = false;
 360	bool crcb_mode = false;
 361	u32 val;
 362
 363	win_data = &ctx->win_data[win];
 364
 365	switch (win_data->pixel_format) {
 366	case DRM_FORMAT_NV12MT:
 367		tiled_mode = true;
 368	case DRM_FORMAT_NV12:
 369		crcb_mode = false;
 370		buf_num = 2;
 371		break;
 372	/* TODO: single buffer format NV12, NV21 */
 373	default:
 374		/* ignore pixel format at disable time */
 375		if (!win_data->dma_addr)
 376			break;
 377
 378		DRM_ERROR("pixel format for vp is wrong [%d].\n",
 379				win_data->pixel_format);
 380		return;
 381	}
 382
 383	/* scaling feature: (src << 16) / dst */
 384	x_ratio = (win_data->src_width << 16) / win_data->crtc_width;
 385	y_ratio = (win_data->src_height << 16) / win_data->crtc_height;
 386
 387	if (buf_num == 2) {
 388		luma_addr[0] = win_data->dma_addr;
 389		chroma_addr[0] = win_data->chroma_dma_addr;
 390	} else {
 391		luma_addr[0] = win_data->dma_addr;
 392		chroma_addr[0] = win_data->dma_addr
 393			+ (win_data->fb_width * win_data->fb_height);
 394	}
 395
 396	if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE) {
 397		ctx->interlace = true;
 398		if (tiled_mode) {
 399			luma_addr[1] = luma_addr[0] + 0x40;
 400			chroma_addr[1] = chroma_addr[0] + 0x40;
 401		} else {
 402			luma_addr[1] = luma_addr[0] + win_data->fb_width;
 403			chroma_addr[1] = chroma_addr[0] + win_data->fb_width;
 404		}
 405	} else {
 406		ctx->interlace = false;
 407		luma_addr[1] = 0;
 408		chroma_addr[1] = 0;
 409	}
 410
 411	spin_lock_irqsave(&res->reg_slock, flags);
 412	mixer_vsync_set_update(ctx, false);
 413
 414	/* interlace or progressive scan mode */
 415	val = (ctx->interlace ? ~0 : 0);
 416	vp_reg_writemask(res, VP_MODE, val, VP_MODE_LINE_SKIP);
 417
 418	/* setup format */
 419	val = (crcb_mode ? VP_MODE_NV21 : VP_MODE_NV12);
 420	val |= (tiled_mode ? VP_MODE_MEM_TILED : VP_MODE_MEM_LINEAR);
 421	vp_reg_writemask(res, VP_MODE, val, VP_MODE_FMT_MASK);
 422
 423	/* setting size of input image */
 424	vp_reg_write(res, VP_IMG_SIZE_Y, VP_IMG_HSIZE(win_data->fb_width) |
 425		VP_IMG_VSIZE(win_data->fb_height));
 426	/* chroma height has to reduced by 2 to avoid chroma distorions */
 427	vp_reg_write(res, VP_IMG_SIZE_C, VP_IMG_HSIZE(win_data->fb_width) |
 428		VP_IMG_VSIZE(win_data->fb_height / 2));
 429
 430	vp_reg_write(res, VP_SRC_WIDTH, win_data->src_width);
 431	vp_reg_write(res, VP_SRC_HEIGHT, win_data->src_height);
 432	vp_reg_write(res, VP_SRC_H_POSITION,
 433			VP_SRC_H_POSITION_VAL(win_data->fb_x));
 434	vp_reg_write(res, VP_SRC_V_POSITION, win_data->fb_y);
 435
 436	vp_reg_write(res, VP_DST_WIDTH, win_data->crtc_width);
 437	vp_reg_write(res, VP_DST_H_POSITION, win_data->crtc_x);
 438	if (ctx->interlace) {
 439		vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height / 2);
 440		vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y / 2);
 441	} else {
 442		vp_reg_write(res, VP_DST_HEIGHT, win_data->crtc_height);
 443		vp_reg_write(res, VP_DST_V_POSITION, win_data->crtc_y);
 444	}
 445
 446	vp_reg_write(res, VP_H_RATIO, x_ratio);
 447	vp_reg_write(res, VP_V_RATIO, y_ratio);
 448
 449	vp_reg_write(res, VP_ENDIAN_MODE, VP_ENDIAN_MODE_LITTLE);
 450
 451	/* set buffer address to vp */
 452	vp_reg_write(res, VP_TOP_Y_PTR, luma_addr[0]);
 453	vp_reg_write(res, VP_BOT_Y_PTR, luma_addr[1]);
 454	vp_reg_write(res, VP_TOP_C_PTR, chroma_addr[0]);
 455	vp_reg_write(res, VP_BOT_C_PTR, chroma_addr[1]);
 456
 457	mixer_cfg_scan(ctx, win_data->mode_height);
 458	mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
 459	mixer_cfg_layer(ctx, win, true);
 460	mixer_run(ctx);
 461
 462	mixer_vsync_set_update(ctx, true);
 463	spin_unlock_irqrestore(&res->reg_slock, flags);
 464
 465	vp_regs_dump(ctx);
 466}
 467
 468static void mixer_graph_buffer(struct mixer_context *ctx, int win)
 469{
 470	struct mixer_resources *res = &ctx->mixer_res;
 471	unsigned long flags;
 472	struct hdmi_win_data *win_data;
 473	unsigned int x_ratio, y_ratio;
 474	unsigned int src_x_offset, src_y_offset, dst_x_offset, dst_y_offset;
 475	dma_addr_t dma_addr;
 476	unsigned int fmt;
 477	u32 val;
 478
 479	win_data = &ctx->win_data[win];
 480
 481	#define RGB565 4
 482	#define ARGB1555 5
 483	#define ARGB4444 6
 484	#define ARGB8888 7
 485
 486	switch (win_data->bpp) {
 487	case 16:
 488		fmt = ARGB4444;
 489		break;
 490	case 32:
 491		fmt = ARGB8888;
 492		break;
 493	default:
 494		fmt = ARGB8888;
 495	}
 496
 497	/* 2x scaling feature */
 498	x_ratio = 0;
 499	y_ratio = 0;
 500
 501	dst_x_offset = win_data->crtc_x;
 502	dst_y_offset = win_data->crtc_y;
 503
 504	/* converting dma address base and source offset */
 505	dma_addr = win_data->dma_addr
 506		+ (win_data->fb_x * win_data->bpp >> 3)
 507		+ (win_data->fb_y * win_data->fb_width * win_data->bpp >> 3);
 508	src_x_offset = 0;
 509	src_y_offset = 0;
 510
 511	if (win_data->scan_flags & DRM_MODE_FLAG_INTERLACE)
 512		ctx->interlace = true;
 513	else
 514		ctx->interlace = false;
 515
 516	spin_lock_irqsave(&res->reg_slock, flags);
 517	mixer_vsync_set_update(ctx, false);
 518
 519	/* setup format */
 520	mixer_reg_writemask(res, MXR_GRAPHIC_CFG(win),
 521		MXR_GRP_CFG_FORMAT_VAL(fmt), MXR_GRP_CFG_FORMAT_MASK);
 522
 523	/* setup geometry */
 524	mixer_reg_write(res, MXR_GRAPHIC_SPAN(win), win_data->fb_width);
 525
 526	val  = MXR_GRP_WH_WIDTH(win_data->crtc_width);
 527	val |= MXR_GRP_WH_HEIGHT(win_data->crtc_height);
 528	val |= MXR_GRP_WH_H_SCALE(x_ratio);
 529	val |= MXR_GRP_WH_V_SCALE(y_ratio);
 530	mixer_reg_write(res, MXR_GRAPHIC_WH(win), val);
 531
 532	/* setup offsets in source image */
 533	val  = MXR_GRP_SXY_SX(src_x_offset);
 534	val |= MXR_GRP_SXY_SY(src_y_offset);
 535	mixer_reg_write(res, MXR_GRAPHIC_SXY(win), val);
 536
 537	/* setup offsets in display image */
 538	val  = MXR_GRP_DXY_DX(dst_x_offset);
 539	val |= MXR_GRP_DXY_DY(dst_y_offset);
 540	mixer_reg_write(res, MXR_GRAPHIC_DXY(win), val);
 541
 542	/* set buffer address to mixer */
 543	mixer_reg_write(res, MXR_GRAPHIC_BASE(win), dma_addr);
 544
 545	mixer_cfg_scan(ctx, win_data->mode_height);
 546	mixer_cfg_rgb_fmt(ctx, win_data->mode_height);
 547	mixer_cfg_layer(ctx, win, true);
 548	mixer_run(ctx);
 549
 550	mixer_vsync_set_update(ctx, true);
 551	spin_unlock_irqrestore(&res->reg_slock, flags);
 552}
 553
 554static void vp_win_reset(struct mixer_context *ctx)
 555{
 556	struct mixer_resources *res = &ctx->mixer_res;
 557	int tries = 100;
 558
 559	vp_reg_write(res, VP_SRESET, VP_SRESET_PROCESSING);
 560	for (tries = 100; tries; --tries) {
 561		/* waiting until VP_SRESET_PROCESSING is 0 */
 562		if (~vp_reg_read(res, VP_SRESET) & VP_SRESET_PROCESSING)
 563			break;
 564		mdelay(10);
 565	}
 566	WARN(tries == 0, "failed to reset Video Processor\n");
 567}
 568
 569static void mixer_win_reset(struct mixer_context *ctx)
 570{
 571	struct mixer_resources *res = &ctx->mixer_res;
 572	unsigned long flags;
 573	u32 val; /* value stored to register */
 574
 575	spin_lock_irqsave(&res->reg_slock, flags);
 576	mixer_vsync_set_update(ctx, false);
 577
 578	mixer_reg_writemask(res, MXR_CFG, MXR_CFG_DST_HDMI, MXR_CFG_DST_MASK);
 579
 580	/* set output in RGB888 mode */
 581	mixer_reg_writemask(res, MXR_CFG, MXR_CFG_OUT_RGB888, MXR_CFG_OUT_MASK);
 582
 583	/* 16 beat burst in DMA */
 584	mixer_reg_writemask(res, MXR_STATUS, MXR_STATUS_16_BURST,
 585		MXR_STATUS_BURST_MASK);
 586
 587	/* setting default layer priority: layer1 > layer0 > video
 588	 * because typical usage scenario would be
 589	 * layer1 - OSD
 590	 * layer0 - framebuffer
 591	 * video - video overlay
 592	 */
 593	val = MXR_LAYER_CFG_GRP1_VAL(3);
 594	val |= MXR_LAYER_CFG_GRP0_VAL(2);
 595	val |= MXR_LAYER_CFG_VP_VAL(1);
 596	mixer_reg_write(res, MXR_LAYER_CFG, val);
 597
 598	/* setting background color */
 599	mixer_reg_write(res, MXR_BG_COLOR0, 0x008080);
 600	mixer_reg_write(res, MXR_BG_COLOR1, 0x008080);
 601	mixer_reg_write(res, MXR_BG_COLOR2, 0x008080);
 602
 603	/* setting graphical layers */
 604	val  = MXR_GRP_CFG_COLOR_KEY_DISABLE; /* no blank key */
 605	val |= MXR_GRP_CFG_WIN_BLEND_EN;
 606	val |= MXR_GRP_CFG_BLEND_PRE_MUL;
 607	val |= MXR_GRP_CFG_PIXEL_BLEND_EN;
 608	val |= MXR_GRP_CFG_ALPHA_VAL(0xff); /* non-transparent alpha */
 609
 610	/* the same configuration for both layers */
 611	mixer_reg_write(res, MXR_GRAPHIC_CFG(0), val);
 612	mixer_reg_write(res, MXR_GRAPHIC_CFG(1), val);
 613
 614	/* setting video layers */
 615	val = MXR_GRP_CFG_ALPHA_VAL(0);
 616	mixer_reg_write(res, MXR_VIDEO_CFG, val);
 617
 618	/* configuration of Video Processor Registers */
 619	vp_win_reset(ctx);
 620	vp_default_filter(res);
 621
 622	/* disable all layers */
 623	mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP0_ENABLE);
 624	mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_GRP1_ENABLE);
 625	mixer_reg_writemask(res, MXR_CFG, 0, MXR_CFG_VP_ENABLE);
 626
 627	mixer_vsync_set_update(ctx, true);
 628	spin_unlock_irqrestore(&res->reg_slock, flags);
 629}
 630
 631static void mixer_poweron(struct mixer_context *ctx)
 632{
 633	struct mixer_resources *res = &ctx->mixer_res;
 634
 635	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 636
 637	mutex_lock(&ctx->mixer_mutex);
 638	if (ctx->powered) {
 639		mutex_unlock(&ctx->mixer_mutex);
 640		return;
 641	}
 642	ctx->powered = true;
 643	mutex_unlock(&ctx->mixer_mutex);
 644
 645	pm_runtime_get_sync(ctx->dev);
 646
 647	clk_enable(res->mixer);
 648	clk_enable(res->vp);
 649	clk_enable(res->sclk_mixer);
 650
 651	mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
 652	mixer_win_reset(ctx);
 653}
 654
 655static void mixer_poweroff(struct mixer_context *ctx)
 656{
 657	struct mixer_resources *res = &ctx->mixer_res;
 658
 659	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 660
 661	mutex_lock(&ctx->mixer_mutex);
 662	if (!ctx->powered)
 663		goto out;
 664	mutex_unlock(&ctx->mixer_mutex);
 665
 666	ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
 667
 668	clk_disable(res->mixer);
 669	clk_disable(res->vp);
 670	clk_disable(res->sclk_mixer);
 671
 672	pm_runtime_put_sync(ctx->dev);
 673
 674	mutex_lock(&ctx->mixer_mutex);
 675	ctx->powered = false;
 676
 677out:
 678	mutex_unlock(&ctx->mixer_mutex);
 679}
 680
 681static int mixer_enable_vblank(void *ctx, int pipe)
 682{
 683	struct mixer_context *mixer_ctx = ctx;
 684	struct mixer_resources *res = &mixer_ctx->mixer_res;
 685
 686	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 687
 688	mixer_ctx->pipe = pipe;
 689
 690	/* enable vsync interrupt */
 691	mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
 692			MXR_INT_EN_VSYNC);
 693
 694	return 0;
 695}
 696
 697static void mixer_disable_vblank(void *ctx)
 698{
 699	struct mixer_context *mixer_ctx = ctx;
 700	struct mixer_resources *res = &mixer_ctx->mixer_res;
 701
 702	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 703
 704	/* disable vsync interrupt */
 705	mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 706}
 707
 708static void mixer_dpms(void *ctx, int mode)
 709{
 710	struct mixer_context *mixer_ctx = ctx;
 711
 712	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 713
 714	switch (mode) {
 715	case DRM_MODE_DPMS_ON:
 716		mixer_poweron(mixer_ctx);
 717		break;
 718	case DRM_MODE_DPMS_STANDBY:
 719	case DRM_MODE_DPMS_SUSPEND:
 720	case DRM_MODE_DPMS_OFF:
 721		mixer_poweroff(mixer_ctx);
 722		break;
 723	default:
 724		DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
 725		break;
 726	}
 727}
 728
 729static void mixer_win_mode_set(void *ctx,
 730			      struct exynos_drm_overlay *overlay)
 731{
 732	struct mixer_context *mixer_ctx = ctx;
 733	struct hdmi_win_data *win_data;
 734	int win;
 735
 736	DRM_DEBUG_KMS("[%d] %s\n", __LINE__, __func__);
 737
 738	if (!overlay) {
 739		DRM_ERROR("overlay is NULL\n");
 740		return;
 741	}
 742
 743	DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
 744				 overlay->fb_width, overlay->fb_height,
 745				 overlay->fb_x, overlay->fb_y,
 746				 overlay->crtc_width, overlay->crtc_height,
 747				 overlay->crtc_x, overlay->crtc_y);
 748
 749	win = overlay->zpos;
 750	if (win == DEFAULT_ZPOS)
 751		win = MIXER_DEFAULT_WIN;
 752
 753	if (win < 0 || win > MIXER_WIN_NR) {
 754		DRM_ERROR("mixer window[%d] is wrong\n", win);
 755		return;
 756	}
 757
 758	win_data = &mixer_ctx->win_data[win];
 759
 760	win_data->dma_addr = overlay->dma_addr[0];
 761	win_data->vaddr = overlay->vaddr[0];
 762	win_data->chroma_dma_addr = overlay->dma_addr[1];
 763	win_data->chroma_vaddr = overlay->vaddr[1];
 764	win_data->pixel_format = overlay->pixel_format;
 765	win_data->bpp = overlay->bpp;
 766
 767	win_data->crtc_x = overlay->crtc_x;
 768	win_data->crtc_y = overlay->crtc_y;
 769	win_data->crtc_width = overlay->crtc_width;
 770	win_data->crtc_height = overlay->crtc_height;
 771
 772	win_data->fb_x = overlay->fb_x;
 773	win_data->fb_y = overlay->fb_y;
 774	win_data->fb_width = overlay->fb_width;
 775	win_data->fb_height = overlay->fb_height;
 776	win_data->src_width = overlay->src_width;
 777	win_data->src_height = overlay->src_height;
 778
 779	win_data->mode_width = overlay->mode_width;
 780	win_data->mode_height = overlay->mode_height;
 781
 782	win_data->scan_flags = overlay->scan_flag;
 783}
 784
 785static void mixer_win_commit(void *ctx, int win)
 786{
 787	struct mixer_context *mixer_ctx = ctx;
 788
 789	DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
 790
 791	if (win > 1)
 792		vp_video_buffer(mixer_ctx, win);
 793	else
 794		mixer_graph_buffer(mixer_ctx, win);
 795}
 796
 797static void mixer_win_disable(void *ctx, int win)
 798{
 799	struct mixer_context *mixer_ctx = ctx;
 800	struct mixer_resources *res = &mixer_ctx->mixer_res;
 801	unsigned long flags;
 802
 803	DRM_DEBUG_KMS("[%d] %s, win: %d\n", __LINE__, __func__, win);
 804
 805	spin_lock_irqsave(&res->reg_slock, flags);
 806	mixer_vsync_set_update(mixer_ctx, false);
 807
 808	mixer_cfg_layer(mixer_ctx, win, false);
 809
 810	mixer_vsync_set_update(mixer_ctx, true);
 811	spin_unlock_irqrestore(&res->reg_slock, flags);
 812}
 813
 814static struct exynos_mixer_ops mixer_ops = {
 815	/* manager */
 816	.enable_vblank		= mixer_enable_vblank,
 817	.disable_vblank		= mixer_disable_vblank,
 818	.dpms			= mixer_dpms,
 819
 820	/* overlay */
 821	.win_mode_set		= mixer_win_mode_set,
 822	.win_commit		= mixer_win_commit,
 823	.win_disable		= mixer_win_disable,
 824};
 825
 826/* for pageflip event */
 827static void mixer_finish_pageflip(struct drm_device *drm_dev, int crtc)
 828{
 829	struct exynos_drm_private *dev_priv = drm_dev->dev_private;
 830	struct drm_pending_vblank_event *e, *t;
 831	struct timeval now;
 832	unsigned long flags;
 833	bool is_checked = false;
 834
 835	spin_lock_irqsave(&drm_dev->event_lock, flags);
 836
 837	list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
 838			base.link) {
 839		/* if event's pipe isn't same as crtc then ignore it. */
 840		if (crtc != e->pipe)
 841			continue;
 842
 843		is_checked = true;
 844		do_gettimeofday(&now);
 845		e->event.sequence = 0;
 846		e->event.tv_sec = now.tv_sec;
 847		e->event.tv_usec = now.tv_usec;
 848
 849		list_move_tail(&e->base.link, &e->base.file_priv->event_list);
 850		wake_up_interruptible(&e->base.file_priv->event_wait);
 851	}
 852
 853	if (is_checked)
 854		/*
 855		 * call drm_vblank_put only in case that drm_vblank_get was
 856		 * called.
 857		 */
 858		if (atomic_read(&drm_dev->vblank_refcount[crtc]) > 0)
 859			drm_vblank_put(drm_dev, crtc);
 860
 861	spin_unlock_irqrestore(&drm_dev->event_lock, flags);
 862}
 863
 864static irqreturn_t mixer_irq_handler(int irq, void *arg)
 865{
 866	struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
 867	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
 868	struct mixer_resources *res = &ctx->mixer_res;
 869	u32 val, base, shadow;
 870
 871	spin_lock(&res->reg_slock);
 872
 873	/* read interrupt status for handling and clearing flags for VSYNC */
 874	val = mixer_reg_read(res, MXR_INT_STATUS);
 875
 876	/* handling VSYNC */
 877	if (val & MXR_INT_STATUS_VSYNC) {
 878		/* interlace scan need to check shadow register */
 879		if (ctx->interlace) {
 880			base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
 881			shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
 882			if (base != shadow)
 883				goto out;
 884
 885			base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
 886			shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
 887			if (base != shadow)
 888				goto out;
 889		}
 890
 891		drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
 892		mixer_finish_pageflip(drm_hdmi_ctx->drm_dev, ctx->pipe);
 893	}
 894
 895out:
 896	/* clear interrupts */
 897	if (~val & MXR_INT_EN_VSYNC) {
 898		/* vsync interrupt use different bit for read and clear */
 899		val &= ~MXR_INT_EN_VSYNC;
 900		val |= MXR_INT_CLEAR_VSYNC;
 901	}
 902	mixer_reg_write(res, MXR_INT_STATUS, val);
 903
 904	spin_unlock(&res->reg_slock);
 905
 906	return IRQ_HANDLED;
 907}
 908
 909static int __devinit mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
 910				 struct platform_device *pdev)
 911{
 912	struct mixer_context *mixer_ctx = ctx->ctx;
 913	struct device *dev = &pdev->dev;
 914	struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
 915	struct resource *res;
 916	int ret;
 917
 918	spin_lock_init(&mixer_res->reg_slock);
 919
 920	mixer_res->mixer = clk_get(dev, "mixer");
 921	if (IS_ERR_OR_NULL(mixer_res->mixer)) {
 922		dev_err(dev, "failed to get clock 'mixer'\n");
 923		ret = -ENODEV;
 924		goto fail;
 925	}
 926	mixer_res->vp = clk_get(dev, "vp");
 927	if (IS_ERR_OR_NULL(mixer_res->vp)) {
 928		dev_err(dev, "failed to get clock 'vp'\n");
 929		ret = -ENODEV;
 930		goto fail;
 931	}
 932	mixer_res->sclk_mixer = clk_get(dev, "sclk_mixer");
 933	if (IS_ERR_OR_NULL(mixer_res->sclk_mixer)) {
 934		dev_err(dev, "failed to get clock 'sclk_mixer'\n");
 935		ret = -ENODEV;
 936		goto fail;
 937	}
 938	mixer_res->sclk_hdmi = clk_get(dev, "sclk_hdmi");
 939	if (IS_ERR_OR_NULL(mixer_res->sclk_hdmi)) {
 940		dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
 941		ret = -ENODEV;
 942		goto fail;
 943	}
 944	mixer_res->sclk_dac = clk_get(dev, "sclk_dac");
 945	if (IS_ERR_OR_NULL(mixer_res->sclk_dac)) {
 946		dev_err(dev, "failed to get clock 'sclk_dac'\n");
 947		ret = -ENODEV;
 948		goto fail;
 949	}
 950	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mxr");
 951	if (res == NULL) {
 952		dev_err(dev, "get memory resource failed.\n");
 953		ret = -ENXIO;
 954		goto fail;
 955	}
 956
 957	clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
 958
 959	mixer_res->mixer_regs = ioremap(res->start, resource_size(res));
 960	if (mixer_res->mixer_regs == NULL) {
 961		dev_err(dev, "register mapping failed.\n");
 962		ret = -ENXIO;
 963		goto fail;
 964	}
 965
 966	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vp");
 967	if (res == NULL) {
 968		dev_err(dev, "get memory resource failed.\n");
 969		ret = -ENXIO;
 970		goto fail_mixer_regs;
 971	}
 972
 973	mixer_res->vp_regs = ioremap(res->start, resource_size(res));
 974	if (mixer_res->vp_regs == NULL) {
 975		dev_err(dev, "register mapping failed.\n");
 976		ret = -ENXIO;
 977		goto fail_mixer_regs;
 978	}
 979
 980	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "irq");
 981	if (res == NULL) {
 982		dev_err(dev, "get interrupt resource failed.\n");
 983		ret = -ENXIO;
 984		goto fail_vp_regs;
 985	}
 986
 987	ret = request_irq(res->start, mixer_irq_handler, 0, "drm_mixer", ctx);
 988	if (ret) {
 989		dev_err(dev, "request interrupt failed.\n");
 990		goto fail_vp_regs;
 991	}
 992	mixer_res->irq = res->start;
 993
 994	return 0;
 995
 996fail_vp_regs:
 997	iounmap(mixer_res->vp_regs);
 998
 999fail_mixer_regs:
1000	iounmap(mixer_res->mixer_regs);
1001
1002fail:
1003	if (!IS_ERR_OR_NULL(mixer_res->sclk_dac))
1004		clk_put(mixer_res->sclk_dac);
1005	if (!IS_ERR_OR_NULL(mixer_res->sclk_hdmi))
1006		clk_put(mixer_res->sclk_hdmi);
1007	if (!IS_ERR_OR_NULL(mixer_res->sclk_mixer))
1008		clk_put(mixer_res->sclk_mixer);
1009	if (!IS_ERR_OR_NULL(mixer_res->vp))
1010		clk_put(mixer_res->vp);
1011	if (!IS_ERR_OR_NULL(mixer_res->mixer))
1012		clk_put(mixer_res->mixer);
1013	return ret;
1014}
1015
1016static void mixer_resources_cleanup(struct mixer_context *ctx)
1017{
1018	struct mixer_resources *res = &ctx->mixer_res;
1019
1020	free_irq(res->irq, ctx);
1021
1022	iounmap(res->vp_regs);
1023	iounmap(res->mixer_regs);
1024}
1025
1026static int __devinit mixer_probe(struct platform_device *pdev)
1027{
1028	struct device *dev = &pdev->dev;
1029	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
1030	struct mixer_context *ctx;
1031	int ret;
1032
1033	dev_info(dev, "probe start\n");
1034
1035	drm_hdmi_ctx = kzalloc(sizeof(*drm_hdmi_ctx), GFP_KERNEL);
1036	if (!drm_hdmi_ctx) {
1037		DRM_ERROR("failed to allocate common hdmi context.\n");
1038		return -ENOMEM;
1039	}
1040
1041	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
1042	if (!ctx) {
1043		DRM_ERROR("failed to alloc mixer context.\n");
1044		kfree(drm_hdmi_ctx);
1045		return -ENOMEM;
1046	}
1047
1048	mutex_init(&ctx->mixer_mutex);
1049
1050	ctx->dev = &pdev->dev;
1051	drm_hdmi_ctx->ctx = (void *)ctx;
1052
1053	platform_set_drvdata(pdev, drm_hdmi_ctx);
1054
1055	/* acquire resources: regs, irqs, clocks */
1056	ret = mixer_resources_init(drm_hdmi_ctx, pdev);
1057	if (ret)
1058		goto fail;
1059
1060	/* register specific callback point to common hdmi. */
1061	exynos_mixer_ops_register(&mixer_ops);
1062
1063	pm_runtime_enable(dev);
1064
1065	return 0;
1066
1067
1068fail:
1069	dev_info(dev, "probe failed\n");
1070	return ret;
1071}
1072
1073static int mixer_remove(struct platform_device *pdev)
1074{
1075	struct device *dev = &pdev->dev;
1076	struct exynos_drm_hdmi_context *drm_hdmi_ctx =
1077					platform_get_drvdata(pdev);
1078	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1079
1080	dev_info(dev, "remove successful\n");
1081
1082	pm_runtime_disable(&pdev->dev);
1083
1084	mixer_resources_cleanup(ctx);
1085
1086	return 0;
1087}
1088
1089#ifdef CONFIG_PM_SLEEP
1090static int mixer_suspend(struct device *dev)
1091{
1092	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
1093	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
1094
1095	mixer_poweroff(ctx);
1096
1097	return 0;
1098}
1099#endif
1100
1101static SIMPLE_DEV_PM_OPS(mixer_pm_ops, mixer_suspend, NULL);
1102
1103struct platform_driver mixer_driver = {
1104	.driver = {
1105		.name = "s5p-mixer",
1106		.owner = THIS_MODULE,
1107		.pm = &mixer_pm_ops,
1108	},
1109	.probe = mixer_probe,
1110	.remove = __devexit_p(mixer_remove),
1111};