File Index
Files and directories
Sign in
FILE

exynos_drm_fimd.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/exynos/exynos_drm_fimd.c C
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/* exynos_drm_fimd.c
   3 *
   4 * Copyright (C) 2011 Samsung Electronics Co.Ltd
   5 * Authors:
   6 *	Joonyoung Shim <jy0922.shim@samsung.com>
   7 *	Inki Dae <inki.dae@samsung.com>
   8 */
   9
  10#include <linux/clk.h>
  11#include <linux/component.h>
  12#include <linux/kernel.h>
  13#include <linux/mfd/syscon.h>
  14#include <linux/of.h>
  15#include <linux/platform_device.h>
  16#include <linux/pm_runtime.h>
  17#include <linux/regmap.h>
  18
  19#include <video/of_display_timing.h>
  20#include <video/of_videomode.h>
  21#include <video/samsung_fimd.h>
  22
  23#include <drm/drm_blend.h>
  24#include <drm/drm_fourcc.h>
  25#include <drm/drm_framebuffer.h>
  26#include <drm/drm_print.h>
  27#include <drm/drm_vblank.h>
  28#include <drm/exynos_drm.h>
  29
  30#include "exynos_drm_crtc.h"
  31#include "exynos_drm_drv.h"
  32#include "exynos_drm_fb.h"
  33#include "exynos_drm_plane.h"
  34
  35/*
  36 * FIMD stands for Fully Interactive Mobile Display and
  37 * as a display controller, it transfers contents drawn on memory
  38 * to a LCD Panel through Display Interfaces such as RGB or
  39 * CPU Interface.
  40 */
  41
  42#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
  43
  44/* position control register for hardware window 0, 2 ~ 4.*/
  45#define VIDOSD_A(win)		(VIDOSD_BASE + 0x00 + (win) * 16)
  46#define VIDOSD_B(win)		(VIDOSD_BASE + 0x04 + (win) * 16)
  47/*
  48 * size control register for hardware windows 0 and alpha control register
  49 * for hardware windows 1 ~ 4
  50 */
  51#define VIDOSD_C(win)		(VIDOSD_BASE + 0x08 + (win) * 16)
  52/* size control register for hardware windows 1 ~ 2. */
  53#define VIDOSD_D(win)		(VIDOSD_BASE + 0x0C + (win) * 16)
  54
  55#define VIDWnALPHA0(win)	(VIDW_ALPHA + 0x00 + (win) * 8)
  56#define VIDWnALPHA1(win)	(VIDW_ALPHA + 0x04 + (win) * 8)
  57
  58#define VIDWx_BUF_START(win, buf)	(VIDW_BUF_START(buf) + (win) * 8)
  59#define VIDWx_BUF_START_S(win, buf)	(VIDW_BUF_START_S(buf) + (win) * 8)
  60#define VIDWx_BUF_END(win, buf)		(VIDW_BUF_END(buf) + (win) * 8)
  61#define VIDWx_BUF_SIZE(win, buf)	(VIDW_BUF_SIZE(buf) + (win) * 4)
  62
  63/* color key control register for hardware window 1 ~ 4. */
  64#define WKEYCON0_BASE(x)		((WKEYCON0 + 0x140) + ((x - 1) * 8))
  65/* color key value register for hardware window 1 ~ 4. */
  66#define WKEYCON1_BASE(x)		((WKEYCON1 + 0x140) + ((x - 1) * 8))
  67
  68/* I80 trigger control register */
  69#define TRIGCON				0x1A4
  70#define TRGMODE_ENABLE			(1 << 0)
  71#define SWTRGCMD_ENABLE			(1 << 1)
  72/* Exynos3250, 3472, 5260 5410, 5420 and 5422 only supported. */
  73#define HWTRGEN_ENABLE			(1 << 3)
  74#define HWTRGMASK_ENABLE		(1 << 4)
  75/* Exynos3250, 3472, 5260, 5420 and 5422 only supported. */
  76#define HWTRIGEN_PER_ENABLE		(1 << 31)
  77
  78/* display mode change control register except exynos4 */
  79#define VIDOUT_CON			0x000
  80#define VIDOUT_CON_F_I80_LDI0		(0x2 << 8)
  81
  82/* I80 interface control for main LDI register */
  83#define I80IFCONFAx(x)			(0x1B0 + (x) * 4)
  84#define I80IFCONFBx(x)			(0x1B8 + (x) * 4)
  85#define LCD_CS_SETUP(x)			((x) << 16)
  86#define LCD_WR_SETUP(x)			((x) << 12)
  87#define LCD_WR_ACTIVE(x)		((x) << 8)
  88#define LCD_WR_HOLD(x)			((x) << 4)
  89#define I80IFEN_ENABLE			(1 << 0)
  90
  91/* FIMD has totally five hardware windows. */
  92#define WINDOWS_NR	5
  93
  94/* HW trigger flag on i80 panel. */
  95#define I80_HW_TRG     (1 << 1)
  96
  97struct fimd_driver_data {
  98	unsigned int timing_base;
  99	unsigned int lcdblk_offset;
 100	unsigned int lcdblk_vt_shift;
 101	unsigned int lcdblk_bypass_shift;
 102	unsigned int lcdblk_mic_bypass_shift;
 103	unsigned int trg_type;
 104
 105	unsigned int has_shadowcon:1;
 106	unsigned int has_clksel:1;
 107	unsigned int has_limited_fmt:1;
 108	unsigned int has_vidoutcon:1;
 109	unsigned int has_vtsel:1;
 110	unsigned int has_mic_bypass:1;
 111	unsigned int has_dp_clk:1;
 112	unsigned int has_hw_trigger:1;
 113	unsigned int has_trigger_per_te:1;
 114	unsigned int has_bgr_support:1;
 115};
 116
 117static struct fimd_driver_data s3c64xx_fimd_driver_data = {
 118	.timing_base = 0x0,
 119	.has_clksel = 1,
 120	.has_limited_fmt = 1,
 121};
 122
 123static struct fimd_driver_data s5pv210_fimd_driver_data = {
 124	.timing_base = 0x0,
 125	.has_shadowcon = 1,
 126	.has_clksel = 1,
 127};
 128
 129static struct fimd_driver_data exynos3_fimd_driver_data = {
 130	.timing_base = 0x20000,
 131	.lcdblk_offset = 0x210,
 132	.lcdblk_bypass_shift = 1,
 133	.has_shadowcon = 1,
 134	.has_vidoutcon = 1,
 135};
 136
 137static struct fimd_driver_data exynos4_fimd_driver_data = {
 138	.timing_base = 0x0,
 139	.lcdblk_offset = 0x210,
 140	.lcdblk_vt_shift = 10,
 141	.lcdblk_bypass_shift = 1,
 142	.has_shadowcon = 1,
 143	.has_vtsel = 1,
 144	.has_bgr_support = 1,
 145};
 146
 147static struct fimd_driver_data exynos5_fimd_driver_data = {
 148	.timing_base = 0x20000,
 149	.lcdblk_offset = 0x214,
 150	.lcdblk_vt_shift = 24,
 151	.lcdblk_bypass_shift = 15,
 152	.has_shadowcon = 1,
 153	.has_vidoutcon = 1,
 154	.has_vtsel = 1,
 155	.has_dp_clk = 1,
 156	.has_bgr_support = 1,
 157};
 158
 159static struct fimd_driver_data exynos5420_fimd_driver_data = {
 160	.timing_base = 0x20000,
 161	.lcdblk_offset = 0x214,
 162	.lcdblk_vt_shift = 24,
 163	.lcdblk_bypass_shift = 15,
 164	.lcdblk_mic_bypass_shift = 11,
 165	.has_shadowcon = 1,
 166	.has_vidoutcon = 1,
 167	.has_vtsel = 1,
 168	.has_mic_bypass = 1,
 169	.has_dp_clk = 1,
 170	.has_bgr_support = 1,
 171};
 172
 173struct fimd_context {
 174	struct device			*dev;
 175	struct drm_device		*drm_dev;
 176	void				*dma_priv;
 177	struct exynos_drm_crtc		*crtc;
 178	struct exynos_drm_plane		planes[WINDOWS_NR];
 179	struct exynos_drm_plane_config	configs[WINDOWS_NR];
 180	struct clk			*bus_clk;
 181	struct clk			*lcd_clk;
 182	void __iomem			*regs;
 183	struct regmap			*sysreg;
 184	unsigned long			irq_flags;
 185	u32				vidcon0;
 186	u32				vidcon1;
 187	u32				vidout_con;
 188	u32				i80ifcon;
 189	bool				i80_if;
 190	bool				suspended;
 191	bool				dp_clk_enabled;
 192	wait_queue_head_t		wait_vsync_queue;
 193	atomic_t			wait_vsync_event;
 194	atomic_t			win_updated;
 195	atomic_t			triggering;
 196	u32				clkdiv;
 197
 198	const struct fimd_driver_data *driver_data;
 199	struct drm_encoder *encoder;
 200	struct exynos_drm_clk		dp_clk;
 201};
 202
 203static const struct of_device_id fimd_driver_dt_match[] = {
 204	{ .compatible = "samsung,s3c6400-fimd",
 205	  .data = &s3c64xx_fimd_driver_data },
 206	{ .compatible = "samsung,s5pv210-fimd",
 207	  .data = &s5pv210_fimd_driver_data },
 208	{ .compatible = "samsung,exynos3250-fimd",
 209	  .data = &exynos3_fimd_driver_data },
 210	{ .compatible = "samsung,exynos4210-fimd",
 211	  .data = &exynos4_fimd_driver_data },
 212	{ .compatible = "samsung,exynos5250-fimd",
 213	  .data = &exynos5_fimd_driver_data },
 214	{ .compatible = "samsung,exynos5420-fimd",
 215	  .data = &exynos5420_fimd_driver_data },
 216	{},
 217};
 218MODULE_DEVICE_TABLE(of, fimd_driver_dt_match);
 219
 220static const enum drm_plane_type fimd_win_types[WINDOWS_NR] = {
 221	DRM_PLANE_TYPE_PRIMARY,
 222	DRM_PLANE_TYPE_OVERLAY,
 223	DRM_PLANE_TYPE_OVERLAY,
 224	DRM_PLANE_TYPE_OVERLAY,
 225	DRM_PLANE_TYPE_CURSOR,
 226};
 227
 228static const uint32_t fimd_formats[] = {
 229	DRM_FORMAT_C8,
 230	DRM_FORMAT_XRGB1555,
 231	DRM_FORMAT_RGB565,
 232	DRM_FORMAT_XRGB8888,
 233	DRM_FORMAT_ARGB8888,
 234};
 235
 236static const uint32_t fimd_extended_formats[] = {
 237	DRM_FORMAT_C8,
 238	DRM_FORMAT_XRGB1555,
 239	DRM_FORMAT_XBGR1555,
 240	DRM_FORMAT_RGB565,
 241	DRM_FORMAT_BGR565,
 242	DRM_FORMAT_XRGB8888,
 243	DRM_FORMAT_XBGR8888,
 244	DRM_FORMAT_ARGB8888,
 245	DRM_FORMAT_ABGR8888,
 246};
 247
 248static const unsigned int capabilities[WINDOWS_NR] = {
 249	0,
 250	EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
 251	EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
 252	EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
 253	EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND,
 254};
 255
 256static inline void fimd_set_bits(struct fimd_context *ctx, u32 reg, u32 mask,
 257				 u32 val)
 258{
 259	val = (val & mask) | (readl(ctx->regs + reg) & ~mask);
 260	writel(val, ctx->regs + reg);
 261}
 262
 263static int fimd_enable_vblank(struct exynos_drm_crtc *crtc)
 264{
 265	struct fimd_context *ctx = crtc->ctx;
 266	u32 val;
 267
 268	if (ctx->suspended)
 269		return -EPERM;
 270
 271	if (!test_and_set_bit(0, &ctx->irq_flags)) {
 272		val = readl(ctx->regs + VIDINTCON0);
 273
 274		val |= VIDINTCON0_INT_ENABLE;
 275
 276		if (ctx->i80_if) {
 277			val |= VIDINTCON0_INT_I80IFDONE;
 278			val |= VIDINTCON0_INT_SYSMAINCON;
 279			val &= ~VIDINTCON0_INT_SYSSUBCON;
 280		} else {
 281			val |= VIDINTCON0_INT_FRAME;
 282
 283			val &= ~VIDINTCON0_FRAMESEL0_MASK;
 284			val |= VIDINTCON0_FRAMESEL0_FRONTPORCH;
 285			val &= ~VIDINTCON0_FRAMESEL1_MASK;
 286			val |= VIDINTCON0_FRAMESEL1_NONE;
 287		}
 288
 289		writel(val, ctx->regs + VIDINTCON0);
 290	}
 291
 292	return 0;
 293}
 294
 295static void fimd_disable_vblank(struct exynos_drm_crtc *crtc)
 296{
 297	struct fimd_context *ctx = crtc->ctx;
 298	u32 val;
 299
 300	if (ctx->suspended)
 301		return;
 302
 303	if (test_and_clear_bit(0, &ctx->irq_flags)) {
 304		val = readl(ctx->regs + VIDINTCON0);
 305
 306		val &= ~VIDINTCON0_INT_ENABLE;
 307
 308		if (ctx->i80_if) {
 309			val &= ~VIDINTCON0_INT_I80IFDONE;
 310			val &= ~VIDINTCON0_INT_SYSMAINCON;
 311			val &= ~VIDINTCON0_INT_SYSSUBCON;
 312		} else
 313			val &= ~VIDINTCON0_INT_FRAME;
 314
 315		writel(val, ctx->regs + VIDINTCON0);
 316	}
 317}
 318
 319static void fimd_wait_for_vblank(struct exynos_drm_crtc *crtc)
 320{
 321	struct fimd_context *ctx = crtc->ctx;
 322
 323	if (ctx->suspended)
 324		return;
 325
 326	atomic_set(&ctx->wait_vsync_event, 1);
 327
 328	/*
 329	 * wait for FIMD to signal VSYNC interrupt or return after
 330	 * timeout which is set to 50ms (refresh rate of 20).
 331	 */
 332	if (!wait_event_timeout(ctx->wait_vsync_queue,
 333				!atomic_read(&ctx->wait_vsync_event),
 334				HZ/20))
 335		DRM_DEV_DEBUG_KMS(ctx->dev, "vblank wait timed out.\n");
 336}
 337
 338static void fimd_enable_video_output(struct fimd_context *ctx, unsigned int win,
 339					bool enable)
 340{
 341	u32 val = readl(ctx->regs + WINCON(win));
 342
 343	if (enable)
 344		val |= WINCONx_ENWIN;
 345	else
 346		val &= ~WINCONx_ENWIN;
 347
 348	writel(val, ctx->regs + WINCON(win));
 349}
 350
 351static void fimd_enable_shadow_channel_path(struct fimd_context *ctx,
 352						unsigned int win,
 353						bool enable)
 354{
 355	u32 val = readl(ctx->regs + SHADOWCON);
 356
 357	if (enable)
 358		val |= SHADOWCON_CHx_ENABLE(win);
 359	else
 360		val &= ~SHADOWCON_CHx_ENABLE(win);
 361
 362	writel(val, ctx->regs + SHADOWCON);
 363}
 364
 365static int fimd_clear_channels(struct exynos_drm_crtc *crtc)
 366{
 367	struct fimd_context *ctx = crtc->ctx;
 368	unsigned int win, ch_enabled = 0;
 369	int ret;
 370
 371	/* Hardware is in unknown state, so ensure it gets enabled properly */
 372	ret = pm_runtime_resume_and_get(ctx->dev);
 373	if (ret < 0) {
 374		dev_err(ctx->dev, "failed to enable FIMD device.\n");
 375		return ret;
 376	}
 377
 378	clk_prepare_enable(ctx->bus_clk);
 379	clk_prepare_enable(ctx->lcd_clk);
 380
 381	/* Check if any channel is enabled. */
 382	for (win = 0; win < WINDOWS_NR; win++) {
 383		u32 val = readl(ctx->regs + WINCON(win));
 384
 385		if (val & WINCONx_ENWIN) {
 386			fimd_enable_video_output(ctx, win, false);
 387
 388			if (ctx->driver_data->has_shadowcon)
 389				fimd_enable_shadow_channel_path(ctx, win,
 390								false);
 391
 392			ch_enabled = 1;
 393		}
 394	}
 395
 396	/* Wait for vsync, as disable channel takes effect at next vsync */
 397	if (ch_enabled) {
 398		ctx->suspended = false;
 399
 400		fimd_enable_vblank(ctx->crtc);
 401		fimd_wait_for_vblank(ctx->crtc);
 402		fimd_disable_vblank(ctx->crtc);
 403
 404		ctx->suspended = true;
 405	}
 406
 407	clk_disable_unprepare(ctx->lcd_clk);
 408	clk_disable_unprepare(ctx->bus_clk);
 409
 410	pm_runtime_put(ctx->dev);
 411
 412	return 0;
 413}
 414
 415
 416static int fimd_atomic_check(struct exynos_drm_crtc *crtc,
 417		struct drm_crtc_state *state)
 418{
 419	struct drm_display_mode *mode = &state->adjusted_mode;
 420	struct fimd_context *ctx = crtc->ctx;
 421	unsigned long ideal_clk, lcd_rate;
 422	u32 clkdiv;
 423
 424	if (mode->clock == 0) {
 425		DRM_DEV_ERROR(ctx->dev, "Mode has zero clock value.\n");
 426		return -EINVAL;
 427	}
 428
 429	ideal_clk = mode->clock * 1000;
 430
 431	if (ctx->i80_if) {
 432		/*
 433		 * The frame done interrupt should be occurred prior to the
 434		 * next TE signal.
 435		 */
 436		ideal_clk *= 2;
 437	}
 438
 439	lcd_rate = clk_get_rate(ctx->lcd_clk);
 440	if (2 * lcd_rate < ideal_clk) {
 441		DRM_DEV_ERROR(ctx->dev,
 442			      "sclk_fimd clock too low(%lu) for requested pixel clock(%lu)\n",
 443			      lcd_rate, ideal_clk);
 444		return -EINVAL;
 445	}
 446
 447	/* Find the clock divider value that gets us closest to ideal_clk */
 448	clkdiv = DIV_ROUND_CLOSEST(lcd_rate, ideal_clk);
 449	if (clkdiv >= 0x200) {
 450		DRM_DEV_ERROR(ctx->dev, "requested pixel clock(%lu) too low\n",
 451			      ideal_clk);
 452		return -EINVAL;
 453	}
 454
 455	ctx->clkdiv = (clkdiv < 0x100) ? clkdiv : 0xff;
 456
 457	return 0;
 458}
 459
 460static void fimd_setup_trigger(struct fimd_context *ctx)
 461{
 462	void __iomem *timing_base = ctx->regs + ctx->driver_data->timing_base;
 463	u32 trg_type = ctx->driver_data->trg_type;
 464	u32 val = readl(timing_base + TRIGCON);
 465
 466	val &= ~(TRGMODE_ENABLE);
 467
 468	if (trg_type == I80_HW_TRG) {
 469		if (ctx->driver_data->has_hw_trigger)
 470			val |= HWTRGEN_ENABLE | HWTRGMASK_ENABLE;
 471		if (ctx->driver_data->has_trigger_per_te)
 472			val |= HWTRIGEN_PER_ENABLE;
 473	} else {
 474		val |= TRGMODE_ENABLE;
 475	}
 476
 477	writel(val, timing_base + TRIGCON);
 478}
 479
 480static void fimd_commit(struct exynos_drm_crtc *crtc)
 481{
 482	struct fimd_context *ctx = crtc->ctx;
 483	struct drm_display_mode *mode = &crtc->base.state->adjusted_mode;
 484	const struct fimd_driver_data *driver_data = ctx->driver_data;
 485	void __iomem *timing_base = ctx->regs + driver_data->timing_base;
 486	u32 val;
 487
 488	if (ctx->suspended)
 489		return;
 490
 491	/* nothing to do if we haven't set the mode yet */
 492	if (mode->htotal == 0 || mode->vtotal == 0)
 493		return;
 494
 495	if (ctx->i80_if) {
 496		val = ctx->i80ifcon | I80IFEN_ENABLE;
 497		writel(val, timing_base + I80IFCONFAx(0));
 498
 499		/* disable auto frame rate */
 500		writel(0, timing_base + I80IFCONFBx(0));
 501
 502		/* set video type selection to I80 interface */
 503		if (driver_data->has_vtsel && ctx->sysreg &&
 504				regmap_update_bits(ctx->sysreg,
 505					driver_data->lcdblk_offset,
 506					0x3 << driver_data->lcdblk_vt_shift,
 507					0x1 << driver_data->lcdblk_vt_shift)) {
 508			DRM_DEV_ERROR(ctx->dev,
 509				      "Failed to update sysreg for I80 i/f.\n");
 510			return;
 511		}
 512	} else {
 513		int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd;
 514		u32 vidcon1;
 515
 516		/* setup polarity values */
 517		vidcon1 = ctx->vidcon1;
 518		if (mode->flags & DRM_MODE_FLAG_NVSYNC)
 519			vidcon1 |= VIDCON1_INV_VSYNC;
 520		if (mode->flags & DRM_MODE_FLAG_NHSYNC)
 521			vidcon1 |= VIDCON1_INV_HSYNC;
 522		writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
 523
 524		/* setup vertical timing values. */
 525		vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
 526		vbpd = mode->crtc_vtotal - mode->crtc_vsync_end;
 527		vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay;
 528
 529		val = VIDTCON0_VBPD(vbpd - 1) |
 530			VIDTCON0_VFPD(vfpd - 1) |
 531			VIDTCON0_VSPW(vsync_len - 1);
 532		writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
 533
 534		/* setup horizontal timing values.  */
 535		hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
 536		hbpd = mode->crtc_htotal - mode->crtc_hsync_end;
 537		hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay;
 538
 539		val = VIDTCON1_HBPD(hbpd - 1) |
 540			VIDTCON1_HFPD(hfpd - 1) |
 541			VIDTCON1_HSPW(hsync_len - 1);
 542		writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
 543	}
 544
 545	if (driver_data->has_vidoutcon)
 546		writel(ctx->vidout_con, timing_base + VIDOUT_CON);
 547
 548	/* set bypass selection */
 549	if (ctx->sysreg && regmap_update_bits(ctx->sysreg,
 550				driver_data->lcdblk_offset,
 551				0x1 << driver_data->lcdblk_bypass_shift,
 552				0x1 << driver_data->lcdblk_bypass_shift)) {
 553		DRM_DEV_ERROR(ctx->dev,
 554			      "Failed to update sysreg for bypass setting.\n");
 555		return;
 556	}
 557
 558	/* TODO: When MIC is enabled for display path, the lcdblk_mic_bypass
 559	 * bit should be cleared.
 560	 */
 561	if (driver_data->has_mic_bypass && ctx->sysreg &&
 562	    regmap_update_bits(ctx->sysreg,
 563				driver_data->lcdblk_offset,
 564				0x1 << driver_data->lcdblk_mic_bypass_shift,
 565				0x1 << driver_data->lcdblk_mic_bypass_shift)) {
 566		DRM_DEV_ERROR(ctx->dev,
 567			      "Failed to update sysreg for bypass mic.\n");
 568		return;
 569	}
 570
 571	/* setup horizontal and vertical display size. */
 572	val = VIDTCON2_LINEVAL(mode->vdisplay - 1) |
 573	       VIDTCON2_HOZVAL(mode->hdisplay - 1) |
 574	       VIDTCON2_LINEVAL_E(mode->vdisplay - 1) |
 575	       VIDTCON2_HOZVAL_E(mode->hdisplay - 1);
 576	writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
 577
 578	fimd_setup_trigger(ctx);
 579
 580	/*
 581	 * fields of register with prefix '_F' would be updated
 582	 * at vsync(same as dma start)
 583	 */
 584	val = ctx->vidcon0;
 585	val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
 586
 587	if (ctx->driver_data->has_clksel)
 588		val |= VIDCON0_CLKSEL_LCD;
 589
 590	if (ctx->clkdiv > 1)
 591		val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
 592
 593	writel(val, ctx->regs + VIDCON0);
 594}
 595
 596static void fimd_win_set_bldeq(struct fimd_context *ctx, unsigned int win,
 597			       unsigned int alpha, unsigned int pixel_alpha)
 598{
 599	u32 mask = BLENDEQ_A_FUNC_F(0xf) | BLENDEQ_B_FUNC_F(0xf);
 600	u32 val = 0;
 601
 602	switch (pixel_alpha) {
 603	case DRM_MODE_BLEND_PIXEL_NONE:
 604	case DRM_MODE_BLEND_COVERAGE:
 605		val |= BLENDEQ_A_FUNC_F(BLENDEQ_ALPHA_A);
 606		val |= BLENDEQ_B_FUNC_F(BLENDEQ_ONE_MINUS_ALPHA_A);
 607		break;
 608	case DRM_MODE_BLEND_PREMULTI:
 609	default:
 610		if (alpha != DRM_BLEND_ALPHA_OPAQUE) {
 611			val |= BLENDEQ_A_FUNC_F(BLENDEQ_ALPHA0);
 612			val |= BLENDEQ_B_FUNC_F(BLENDEQ_ONE_MINUS_ALPHA_A);
 613		} else {
 614			val |= BLENDEQ_A_FUNC_F(BLENDEQ_ONE);
 615			val |= BLENDEQ_B_FUNC_F(BLENDEQ_ONE_MINUS_ALPHA_A);
 616		}
 617		break;
 618	}
 619	fimd_set_bits(ctx, BLENDEQx(win), mask, val);
 620}
 621
 622static void fimd_win_set_bldmod(struct fimd_context *ctx, unsigned int win,
 623				unsigned int alpha, unsigned int pixel_alpha)
 624{
 625	u32 win_alpha_l = (alpha >> 8) & 0xf;
 626	u32 win_alpha_h = alpha >> 12;
 627	u32 val = 0;
 628
 629	switch (pixel_alpha) {
 630	case DRM_MODE_BLEND_PIXEL_NONE:
 631		break;
 632	case DRM_MODE_BLEND_COVERAGE:
 633	case DRM_MODE_BLEND_PREMULTI:
 634	default:
 635		val |= WINCON1_ALPHA_SEL;
 636		val |= WINCON1_BLD_PIX;
 637		val |= WINCON1_ALPHA_MUL;
 638		break;
 639	}
 640	fimd_set_bits(ctx, WINCON(win), WINCONx_BLEND_MODE_MASK, val);
 641
 642	/* OSD alpha */
 643	val = VIDISD14C_ALPHA0_R(win_alpha_h) |
 644		VIDISD14C_ALPHA0_G(win_alpha_h) |
 645		VIDISD14C_ALPHA0_B(win_alpha_h) |
 646		VIDISD14C_ALPHA1_R(0x0) |
 647		VIDISD14C_ALPHA1_G(0x0) |
 648		VIDISD14C_ALPHA1_B(0x0);
 649	writel(val, ctx->regs + VIDOSD_C(win));
 650
 651	val = VIDW_ALPHA_R(win_alpha_l) | VIDW_ALPHA_G(win_alpha_l) |
 652		VIDW_ALPHA_B(win_alpha_l);
 653	writel(val, ctx->regs + VIDWnALPHA0(win));
 654
 655	val = VIDW_ALPHA_R(0x0) | VIDW_ALPHA_G(0x0) |
 656		VIDW_ALPHA_B(0x0);
 657	writel(val, ctx->regs + VIDWnALPHA1(win));
 658
 659	fimd_set_bits(ctx, BLENDCON, BLENDCON_NEW_MASK,
 660			BLENDCON_NEW_8BIT_ALPHA_VALUE);
 661}
 662
 663static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win,
 664				struct drm_framebuffer *fb, int width)
 665{
 666	struct exynos_drm_plane *plane = &ctx->planes[win];
 667	struct exynos_drm_plane_state *state =
 668		to_exynos_plane_state(plane->base.state);
 669	uint32_t pixel_format = fb->format->format;
 670	unsigned int alpha = state->base.alpha;
 671	u32 val = WINCONx_ENWIN;
 672	unsigned int pixel_alpha;
 673
 674	if (fb->format->has_alpha)
 675		pixel_alpha = state->base.pixel_blend_mode;
 676	else
 677		pixel_alpha = DRM_MODE_BLEND_PIXEL_NONE;
 678
 679	/*
 680	 * In case of s3c64xx, window 0 doesn't support alpha channel.
 681	 * So the request format is ARGB8888 then change it to XRGB8888.
 682	 */
 683	if (ctx->driver_data->has_limited_fmt && !win) {
 684		if (pixel_format == DRM_FORMAT_ARGB8888)
 685			pixel_format = DRM_FORMAT_XRGB8888;
 686	}
 687
 688	switch (pixel_format) {
 689	case DRM_FORMAT_C8:
 690		val |= WINCON0_BPPMODE_8BPP_PALETTE;
 691		val |= WINCONx_BURSTLEN_8WORD;
 692		val |= WINCONx_BYTSWP;
 693		break;
 694	case DRM_FORMAT_XRGB1555:
 695	case DRM_FORMAT_XBGR1555:
 696		val |= WINCON0_BPPMODE_16BPP_1555;
 697		val |= WINCONx_HAWSWP;
 698		val |= WINCONx_BURSTLEN_16WORD;
 699		break;
 700	case DRM_FORMAT_RGB565:
 701	case DRM_FORMAT_BGR565:
 702		val |= WINCON0_BPPMODE_16BPP_565;
 703		val |= WINCONx_HAWSWP;
 704		val |= WINCONx_BURSTLEN_16WORD;
 705		break;
 706	case DRM_FORMAT_XRGB8888:
 707	case DRM_FORMAT_XBGR8888:
 708		val |= WINCON0_BPPMODE_24BPP_888;
 709		val |= WINCONx_WSWP;
 710		val |= WINCONx_BURSTLEN_16WORD;
 711		break;
 712	case DRM_FORMAT_ARGB8888:
 713	case DRM_FORMAT_ABGR8888:
 714	default:
 715		val |= WINCON1_BPPMODE_25BPP_A1888;
 716		val |= WINCONx_WSWP;
 717		val |= WINCONx_BURSTLEN_16WORD;
 718		break;
 719	}
 720
 721	switch (pixel_format) {
 722	case DRM_FORMAT_XBGR1555:
 723	case DRM_FORMAT_XBGR8888:
 724	case DRM_FORMAT_ABGR8888:
 725	case DRM_FORMAT_BGR565:
 726		writel(WIN_RGB_ORDER_REVERSE, ctx->regs + WIN_RGB_ORDER(win));
 727		break;
 728	default:
 729		writel(WIN_RGB_ORDER_FORWARD, ctx->regs + WIN_RGB_ORDER(win));
 730		break;
 731	}
 732
 733	/*
 734	 * Setting dma-burst to 16Word causes permanent tearing for very small
 735	 * buffers, e.g. cursor buffer. Burst Mode switching which based on
 736	 * plane size is not recommended as plane size varies a lot towards the
 737	 * end of the screen and rapid movement causes unstable DMA, but it is
 738	 * still better to change dma-burst than displaying garbage.
 739	 */
 740
 741	if (width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
 742		val &= ~WINCONx_BURSTLEN_MASK;
 743		val |= WINCONx_BURSTLEN_4WORD;
 744	}
 745	fimd_set_bits(ctx, WINCON(win), ~WINCONx_BLEND_MODE_MASK, val);
 746
 747	/* hardware window 0 doesn't support alpha channel. */
 748	if (win != 0) {
 749		fimd_win_set_bldmod(ctx, win, alpha, pixel_alpha);
 750		fimd_win_set_bldeq(ctx, win, alpha, pixel_alpha);
 751	}
 752}
 753
 754static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win)
 755{
 756	unsigned int keycon0 = 0, keycon1 = 0;
 757
 758	keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
 759			WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
 760
 761	keycon1 = WxKEYCON1_COLVAL(0xffffffff);
 762
 763	writel(keycon0, ctx->regs + WKEYCON0_BASE(win));
 764	writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
 765}
 766
 767/**
 768 * fimd_shadow_protect_win() - disable updating values from shadow registers at vsync
 769 *
 770 * @ctx: local driver data
 771 * @win: window to protect registers for
 772 * @protect: 1 to protect (disable updates)
 773 */
 774static void fimd_shadow_protect_win(struct fimd_context *ctx,
 775				    unsigned int win, bool protect)
 776{
 777	u32 reg, bits, val;
 778
 779	/*
 780	 * SHADOWCON/PRTCON register is used for enabling timing.
 781	 *
 782	 * for example, once only width value of a register is set,
 783	 * if the dma is started then fimd hardware could malfunction so
 784	 * with protect window setting, the register fields with prefix '_F'
 785	 * wouldn't be updated at vsync also but updated once unprotect window
 786	 * is set.
 787	 */
 788
 789	if (ctx->driver_data->has_shadowcon) {
 790		reg = SHADOWCON;
 791		bits = SHADOWCON_WINx_PROTECT(win);
 792	} else {
 793		reg = PRTCON;
 794		bits = PRTCON_PROTECT;
 795	}
 796
 797	val = readl(ctx->regs + reg);
 798	if (protect)
 799		val |= bits;
 800	else
 801		val &= ~bits;
 802	writel(val, ctx->regs + reg);
 803}
 804
 805static void fimd_atomic_begin(struct exynos_drm_crtc *crtc)
 806{
 807	struct fimd_context *ctx = crtc->ctx;
 808	int i;
 809
 810	if (ctx->suspended)
 811		return;
 812
 813	for (i = 0; i < WINDOWS_NR; i++)
 814		fimd_shadow_protect_win(ctx, i, true);
 815}
 816
 817static void fimd_atomic_flush(struct exynos_drm_crtc *crtc)
 818{
 819	struct fimd_context *ctx = crtc->ctx;
 820	int i;
 821
 822	if (ctx->suspended)
 823		return;
 824
 825	for (i = 0; i < WINDOWS_NR; i++)
 826		fimd_shadow_protect_win(ctx, i, false);
 827
 828	exynos_crtc_handle_event(crtc);
 829}
 830
 831static void fimd_update_plane(struct exynos_drm_crtc *crtc,
 832			      struct exynos_drm_plane *plane)
 833{
 834	struct exynos_drm_plane_state *state =
 835				to_exynos_plane_state(plane->base.state);
 836	struct fimd_context *ctx = crtc->ctx;
 837	struct drm_framebuffer *fb = state->base.fb;
 838	dma_addr_t dma_addr;
 839	unsigned long val, size, offset;
 840	unsigned int last_x, last_y, buf_offsize, line_size;
 841	unsigned int win = plane->index;
 842	unsigned int cpp = fb->format->cpp[0];
 843	unsigned int pitch = fb->pitches[0];
 844
 845	if (ctx->suspended)
 846		return;
 847
 848	offset = state->src.x * cpp;
 849	offset += state->src.y * pitch;
 850
 851	/* buffer start address */
 852	dma_addr = exynos_drm_fb_dma_addr(fb, 0) + offset;
 853	val = (unsigned long)dma_addr;
 854	writel(val, ctx->regs + VIDWx_BUF_START(win, 0));
 855
 856	/* buffer end address */
 857	size = pitch * state->crtc.h;
 858	val = (unsigned long)(dma_addr + size);
 859	writel(val, ctx->regs + VIDWx_BUF_END(win, 0));
 860
 861	DRM_DEV_DEBUG_KMS(ctx->dev,
 862			  "start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n",
 863			  (unsigned long)dma_addr, val, size);
 864	DRM_DEV_DEBUG_KMS(ctx->dev, "ovl_width = %d, ovl_height = %d\n",
 865			  state->crtc.w, state->crtc.h);
 866
 867	/* buffer size */
 868	buf_offsize = pitch - (state->crtc.w * cpp);
 869	line_size = state->crtc.w * cpp;
 870	val = VIDW_BUF_SIZE_OFFSET(buf_offsize) |
 871		VIDW_BUF_SIZE_PAGEWIDTH(line_size) |
 872		VIDW_BUF_SIZE_OFFSET_E(buf_offsize) |
 873		VIDW_BUF_SIZE_PAGEWIDTH_E(line_size);
 874	writel(val, ctx->regs + VIDWx_BUF_SIZE(win, 0));
 875
 876	/* OSD position */
 877	val = VIDOSDxA_TOPLEFT_X(state->crtc.x) |
 878		VIDOSDxA_TOPLEFT_Y(state->crtc.y) |
 879		VIDOSDxA_TOPLEFT_X_E(state->crtc.x) |
 880		VIDOSDxA_TOPLEFT_Y_E(state->crtc.y);
 881	writel(val, ctx->regs + VIDOSD_A(win));
 882
 883	last_x = state->crtc.x + state->crtc.w;
 884	if (last_x)
 885		last_x--;
 886	last_y = state->crtc.y + state->crtc.h;
 887	if (last_y)
 888		last_y--;
 889
 890	val = VIDOSDxB_BOTRIGHT_X(last_x) | VIDOSDxB_BOTRIGHT_Y(last_y) |
 891		VIDOSDxB_BOTRIGHT_X_E(last_x) | VIDOSDxB_BOTRIGHT_Y_E(last_y);
 892
 893	writel(val, ctx->regs + VIDOSD_B(win));
 894
 895	DRM_DEV_DEBUG_KMS(ctx->dev,
 896			  "osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
 897			  state->crtc.x, state->crtc.y, last_x, last_y);
 898
 899	/* OSD size */
 900	if (win != 3 && win != 4) {
 901		u32 offset = VIDOSD_D(win);
 902		if (win == 0)
 903			offset = VIDOSD_C(win);
 904		val = state->crtc.w * state->crtc.h;
 905		writel(val, ctx->regs + offset);
 906
 907		DRM_DEV_DEBUG_KMS(ctx->dev, "osd size = 0x%x\n",
 908				  (unsigned int)val);
 909	}
 910
 911	fimd_win_set_pixfmt(ctx, win, fb, state->src.w);
 912
 913	/* hardware window 0 doesn't support color key. */
 914	if (win != 0)
 915		fimd_win_set_colkey(ctx, win);
 916
 917	fimd_enable_video_output(ctx, win, true);
 918
 919	if (ctx->driver_data->has_shadowcon)
 920		fimd_enable_shadow_channel_path(ctx, win, true);
 921
 922	if (ctx->i80_if)
 923		atomic_set(&ctx->win_updated, 1);
 924}
 925
 926static void fimd_disable_plane(struct exynos_drm_crtc *crtc,
 927			       struct exynos_drm_plane *plane)
 928{
 929	struct fimd_context *ctx = crtc->ctx;
 930	unsigned int win = plane->index;
 931
 932	if (ctx->suspended)
 933		return;
 934
 935	fimd_enable_video_output(ctx, win, false);
 936
 937	if (ctx->driver_data->has_shadowcon)
 938		fimd_enable_shadow_channel_path(ctx, win, false);
 939}
 940
 941static void fimd_atomic_enable(struct exynos_drm_crtc *crtc)
 942{
 943	struct fimd_context *ctx = crtc->ctx;
 944
 945	if (!ctx->suspended)
 946		return;
 947
 948	ctx->suspended = false;
 949
 950	if (pm_runtime_resume_and_get(ctx->dev) < 0) {
 951		dev_warn(ctx->dev, "failed to enable FIMD device.\n");
 952		return;
 953	}
 954
 955	/* if vblank was enabled status, enable it again. */
 956	if (test_and_clear_bit(0, &ctx->irq_flags))
 957		fimd_enable_vblank(ctx->crtc);
 958
 959	fimd_commit(ctx->crtc);
 960}
 961
 962static void fimd_atomic_disable(struct exynos_drm_crtc *crtc)
 963{
 964	struct fimd_context *ctx = crtc->ctx;
 965	int i;
 966
 967	if (ctx->suspended)
 968		return;
 969
 970	/*
 971	 * We need to make sure that all windows are disabled before we
 972	 * suspend that connector. Otherwise we might try to scan from
 973	 * a destroyed buffer later.
 974	 */
 975	for (i = 0; i < WINDOWS_NR; i++)
 976		fimd_disable_plane(crtc, &ctx->planes[i]);
 977
 978	fimd_enable_vblank(crtc);
 979	fimd_wait_for_vblank(crtc);
 980	fimd_disable_vblank(crtc);
 981
 982	writel(0, ctx->regs + VIDCON0);
 983
 984	pm_runtime_put_sync(ctx->dev);
 985	ctx->suspended = true;
 986}
 987
 988static void fimd_trigger(struct device *dev)
 989{
 990	struct fimd_context *ctx = dev_get_drvdata(dev);
 991	const struct fimd_driver_data *driver_data = ctx->driver_data;
 992	void *timing_base = ctx->regs + driver_data->timing_base;
 993	u32 reg;
 994
 995	 /*
 996	  * Skips triggering if in triggering state, because multiple triggering
 997	  * requests can cause panel reset.
 998	  */
 999	if (atomic_read(&ctx->triggering))
1000		return;
1001
1002	/* Enters triggering mode */
1003	atomic_set(&ctx->triggering, 1);
1004
1005	reg = readl(timing_base + TRIGCON);
1006	reg |= (TRGMODE_ENABLE | SWTRGCMD_ENABLE);
1007	writel(reg, timing_base + TRIGCON);
1008
1009	/*
1010	 * Exits triggering mode if vblank is not enabled yet, because when the
1011	 * VIDINTCON0 register is not set, it can not exit from triggering mode.
1012	 */
1013	if (!test_bit(0, &ctx->irq_flags))
1014		atomic_set(&ctx->triggering, 0);
1015}
1016
1017static void fimd_te_handler(struct exynos_drm_crtc *crtc)
1018{
1019	struct fimd_context *ctx = crtc->ctx;
1020	u32 trg_type = ctx->driver_data->trg_type;
1021
1022	/* Checks the crtc is detached already from encoder */
1023	if (!ctx->drm_dev)
1024		return;
1025
1026	if (trg_type == I80_HW_TRG)
1027		goto out;
1028
1029	/*
1030	 * If there is a page flip request, triggers and handles the page flip
1031	 * event so that current fb can be updated into panel GRAM.
1032	 */
1033	if (atomic_add_unless(&ctx->win_updated, -1, 0))
1034		fimd_trigger(ctx->dev);
1035
1036out:
1037	/* Wakes up vsync event queue */
1038	if (atomic_read(&ctx->wait_vsync_event)) {
1039		atomic_set(&ctx->wait_vsync_event, 0);
1040		wake_up(&ctx->wait_vsync_queue);
1041	}
1042
1043	if (test_bit(0, &ctx->irq_flags))
1044		drm_crtc_handle_vblank(&ctx->crtc->base);
1045}
1046
1047static void fimd_dp_clock_enable(struct exynos_drm_clk *clk, bool enable)
1048{
1049	struct fimd_context *ctx = container_of(clk, struct fimd_context,
1050						dp_clk);
1051	u32 val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;
1052
1053	if (enable == ctx->dp_clk_enabled)
1054		return;
1055
1056	if (enable)
1057		pm_runtime_resume_and_get(ctx->dev);
1058
1059	ctx->dp_clk_enabled = enable;
1060	writel(val, ctx->regs + DP_MIE_CLKCON);
1061
1062	if (!enable)
1063		pm_runtime_put(ctx->dev);
1064}
1065
1066static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
1067	.atomic_enable = fimd_atomic_enable,
1068	.atomic_disable = fimd_atomic_disable,
1069	.enable_vblank = fimd_enable_vblank,
1070	.disable_vblank = fimd_disable_vblank,
1071	.atomic_begin = fimd_atomic_begin,
1072	.update_plane = fimd_update_plane,
1073	.disable_plane = fimd_disable_plane,
1074	.atomic_flush = fimd_atomic_flush,
1075	.atomic_check = fimd_atomic_check,
1076	.te_handler = fimd_te_handler,
1077};
1078
1079static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
1080{
1081	struct fimd_context *ctx = (struct fimd_context *)dev_id;
1082	u32 val, clear_bit;
1083
1084	val = readl(ctx->regs + VIDINTCON1);
1085
1086	clear_bit = ctx->i80_if ? VIDINTCON1_INT_I80 : VIDINTCON1_INT_FRAME;
1087	if (val & clear_bit)
1088		writel(clear_bit, ctx->regs + VIDINTCON1);
1089
1090	/* check the crtc is detached already from encoder */
1091	if (!ctx->drm_dev)
1092		goto out;
1093
1094	if (!ctx->i80_if)
1095		drm_crtc_handle_vblank(&ctx->crtc->base);
1096
1097	if (ctx->i80_if) {
1098		/* Exits triggering mode */
1099		atomic_set(&ctx->triggering, 0);
1100	} else {
1101		/* set wait vsync event to zero and wake up queue. */
1102		if (atomic_read(&ctx->wait_vsync_event)) {
1103			atomic_set(&ctx->wait_vsync_event, 0);
1104			wake_up(&ctx->wait_vsync_queue);
1105		}
1106	}
1107
1108out:
1109	return IRQ_HANDLED;
1110}
1111
1112static int fimd_bind(struct device *dev, struct device *master, void *data)
1113{
1114	struct fimd_context *ctx = dev_get_drvdata(dev);
1115	struct drm_device *drm_dev = data;
1116	struct exynos_drm_plane *exynos_plane;
1117	unsigned int i;
1118	int ret;
1119
1120	ctx->drm_dev = drm_dev;
1121
1122	for (i = 0; i < WINDOWS_NR; i++) {
1123		if (ctx->driver_data->has_bgr_support) {
1124			ctx->configs[i].pixel_formats = fimd_extended_formats;
1125			ctx->configs[i].num_pixel_formats = ARRAY_SIZE(fimd_extended_formats);
1126		} else {
1127			ctx->configs[i].pixel_formats = fimd_formats;
1128			ctx->configs[i].num_pixel_formats = ARRAY_SIZE(fimd_formats);
1129		}
1130
1131		ctx->configs[i].zpos = i;
1132		ctx->configs[i].type = fimd_win_types[i];
1133		ctx->configs[i].capabilities = capabilities[i];
1134		ret = exynos_plane_init(drm_dev, &ctx->planes[i], i,
1135					&ctx->configs[i]);
1136		if (ret)
1137			return ret;
1138	}
1139
1140	exynos_plane = &ctx->planes[DEFAULT_WIN];
1141	ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base,
1142			EXYNOS_DISPLAY_TYPE_LCD, &fimd_crtc_ops, ctx);
1143	if (IS_ERR(ctx->crtc))
1144		return PTR_ERR(ctx->crtc);
1145
1146	if (ctx->driver_data->has_dp_clk) {
1147		ctx->dp_clk.enable = fimd_dp_clock_enable;
1148		ctx->crtc->pipe_clk = &ctx->dp_clk;
1149	}
1150
1151	if (ctx->encoder)
1152		exynos_dpi_bind(drm_dev, ctx->encoder);
1153
1154	if (is_drm_iommu_supported(drm_dev)) {
1155		int ret;
1156
1157		ret = fimd_clear_channels(ctx->crtc);
1158		if (ret < 0)
1159			return ret;
1160	}
1161
1162	return exynos_drm_register_dma(drm_dev, dev, &ctx->dma_priv);
1163}
1164
1165static void fimd_unbind(struct device *dev, struct device *master,
1166			void *data)
1167{
1168	struct fimd_context *ctx = dev_get_drvdata(dev);
1169
1170	fimd_atomic_disable(ctx->crtc);
1171
1172	exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev, &ctx->dma_priv);
1173
1174	if (ctx->encoder)
1175		exynos_dpi_remove(ctx->encoder);
1176}
1177
1178static const struct component_ops fimd_component_ops = {
1179	.bind	= fimd_bind,
1180	.unbind = fimd_unbind,
1181};
1182
1183static int fimd_probe(struct platform_device *pdev)
1184{
1185	struct device *dev = &pdev->dev;
1186	struct fimd_context *ctx;
1187	struct device_node *i80_if_timings;
1188	int ret;
1189
1190	if (!dev->of_node)
1191		return -ENODEV;
1192
1193	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
1194	if (!ctx)
1195		return -ENOMEM;
1196
1197	ctx->dev = dev;
1198	ctx->suspended = true;
1199	ctx->driver_data = of_device_get_match_data(dev);
1200
1201	if (of_property_read_bool(dev->of_node, "samsung,invert-vden"))
1202		ctx->vidcon1 |= VIDCON1_INV_VDEN;
1203	if (of_property_read_bool(dev->of_node, "samsung,invert-vclk"))
1204		ctx->vidcon1 |= VIDCON1_INV_VCLK;
1205
1206	i80_if_timings = of_get_child_by_name(dev->of_node, "i80-if-timings");
1207	if (i80_if_timings) {
1208		u32 val;
1209
1210		ctx->i80_if = true;
1211
1212		if (ctx->driver_data->has_vidoutcon)
1213			ctx->vidout_con |= VIDOUT_CON_F_I80_LDI0;
1214		else
1215			ctx->vidcon0 |= VIDCON0_VIDOUT_I80_LDI0;
1216		/*
1217		 * The user manual describes that this "DSI_EN" bit is required
1218		 * to enable I80 24-bit data interface.
1219		 */
1220		ctx->vidcon0 |= VIDCON0_DSI_EN;
1221
1222		if (of_property_read_u32(i80_if_timings, "cs-setup", &val))
1223			val = 0;
1224		ctx->i80ifcon = LCD_CS_SETUP(val);
1225		if (of_property_read_u32(i80_if_timings, "wr-setup", &val))
1226			val = 0;
1227		ctx->i80ifcon |= LCD_WR_SETUP(val);
1228		if (of_property_read_u32(i80_if_timings, "wr-active", &val))
1229			val = 1;
1230		ctx->i80ifcon |= LCD_WR_ACTIVE(val);
1231		if (of_property_read_u32(i80_if_timings, "wr-hold", &val))
1232			val = 0;
1233		ctx->i80ifcon |= LCD_WR_HOLD(val);
1234	}
1235	of_node_put(i80_if_timings);
1236
1237	ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
1238							"samsung,sysreg");
1239	if (IS_ERR(ctx->sysreg)) {
1240		dev_warn(dev, "failed to get system register.\n");
1241		ctx->sysreg = NULL;
1242	}
1243
1244	ctx->bus_clk = devm_clk_get(dev, "fimd");
1245	if (IS_ERR(ctx->bus_clk)) {
1246		dev_err(dev, "failed to get bus clock\n");
1247		return PTR_ERR(ctx->bus_clk);
1248	}
1249
1250	ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
1251	if (IS_ERR(ctx->lcd_clk)) {
1252		dev_err(dev, "failed to get lcd clock\n");
1253		return PTR_ERR(ctx->lcd_clk);
1254	}
1255
1256	ctx->regs = devm_platform_ioremap_resource(pdev, 0);
1257	if (IS_ERR(ctx->regs))
1258		return PTR_ERR(ctx->regs);
1259
1260	ret = platform_get_irq_byname(pdev, ctx->i80_if ? "lcd_sys" : "vsync");
1261	if (ret < 0)
1262		return ret;
1263
1264	ret = devm_request_irq(dev, ret, fimd_irq_handler, 0, "drm_fimd", ctx);
1265	if (ret) {
1266		dev_err(dev, "irq request failed.\n");
1267		return ret;
1268	}
1269
1270	init_waitqueue_head(&ctx->wait_vsync_queue);
1271	atomic_set(&ctx->wait_vsync_event, 0);
1272
1273	platform_set_drvdata(pdev, ctx);
1274
1275	ctx->encoder = exynos_dpi_probe(dev);
1276	if (IS_ERR(ctx->encoder))
1277		return PTR_ERR(ctx->encoder);
1278
1279	pm_runtime_enable(dev);
1280
1281	ret = component_add(dev, &fimd_component_ops);
1282	if (ret)
1283		goto err_disable_pm_runtime;
1284
1285	return ret;
1286
1287err_disable_pm_runtime:
1288	pm_runtime_disable(dev);
1289
1290	return ret;
1291}
1292
1293static void fimd_remove(struct platform_device *pdev)
1294{
1295	pm_runtime_disable(&pdev->dev);
1296
1297	component_del(&pdev->dev, &fimd_component_ops);
1298}
1299
1300static int exynos_fimd_suspend(struct device *dev)
1301{
1302	struct fimd_context *ctx = dev_get_drvdata(dev);
1303
1304	clk_disable_unprepare(ctx->lcd_clk);
1305	clk_disable_unprepare(ctx->bus_clk);
1306
1307	return 0;
1308}
1309
1310static int exynos_fimd_resume(struct device *dev)
1311{
1312	struct fimd_context *ctx = dev_get_drvdata(dev);
1313	int ret;
1314
1315	ret = clk_prepare_enable(ctx->bus_clk);
1316	if (ret < 0) {
1317		DRM_DEV_ERROR(dev,
1318			      "Failed to prepare_enable the bus clk [%d]\n",
1319			      ret);
1320		return ret;
1321	}
1322
1323	ret = clk_prepare_enable(ctx->lcd_clk);
1324	if  (ret < 0) {
1325		DRM_DEV_ERROR(dev,
1326			      "Failed to prepare_enable the lcd clk [%d]\n",
1327			      ret);
1328		return ret;
1329	}
1330
1331	return 0;
1332}
1333
1334static DEFINE_RUNTIME_DEV_PM_OPS(exynos_fimd_pm_ops, exynos_fimd_suspend,
1335				 exynos_fimd_resume, NULL);
1336
1337struct platform_driver fimd_driver = {
1338	.probe		= fimd_probe,
1339	.remove		= fimd_remove,
1340	.driver		= {
1341		.name	= "exynos4-fb",
1342		.pm	= pm_ptr(&exynos_fimd_pm_ops),
1343		.of_match_table = fimd_driver_dt_match,
1344	},
1345};
~/ Read-only file preview.